{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import tensorflow.keras as K\n",
    "import matplotlib.pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.random.seed(11)\n",
    "tf.random.set_seed(11)\n",
    "batch_size = 256\n",
    "max_epochs = 50\n",
    "learning_rate = 1e-3\n",
    "momentum = 8e-1\n",
    "hidden_dim = 128\n",
    "original_dim = 784"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "(x_train, _), (x_test, _) = K.datasets.mnist.load_data()\n",
    "\n",
    "x_train = x_train / 255.\n",
    "x_test = x_test / 255.\n",
    "\n",
    "x_train = x_train.astype(np.float32)\n",
    "x_test = x_test.astype(np.float32)\n",
    "\n",
    "x_train = np.reshape(x_train, (x_train.shape[0], 784))\n",
    "x_test = np.reshape(x_test, (x_test.shape[0], 784))\n",
    "\n",
    "training_dataset = tf.data.Dataset.from_tensor_slices(x_train).batch(batch_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "class Encoder(K.layers.Layer):\n",
    "    def __init__(self, hidden_dim):\n",
    "        super(Encoder, self).__init__()\n",
    "        self.hidden_layer = K.layers.Dense(units=hidden_dim, activation=tf.nn.relu)\n",
    "        \n",
    "    \n",
    "    def call(self, input_features):\n",
    "        activation = self.hidden_layer(input_features)\n",
    "        return activation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "class Decoder(K.layers.Layer):\n",
    "    def __init__(self, hidden_dim, original_dim):\n",
    "        super(Decoder, self).__init__()\n",
    "        self.output_layer = K.layers.Dense(units=original_dim, activation=tf.nn.relu)\n",
    "  \n",
    "    def call(self, encoded):\n",
    "        activation = self.output_layer(encoded)\n",
    "        return activation "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Autoencoder(K.Model):\n",
    "    def __init__(self, hidden_dim, original_dim):\n",
    "        super(Autoencoder, self).__init__()\n",
    "        self.loss = []\n",
    "        self.encoder = Encoder(hidden_dim=hidden_dim)\n",
    "        self.decoder = Decoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
    "\n",
    "    def call(self, input_features):\n",
    "        encoded = self.encoder(input_features)\n",
    "        reconstructed = self.decoder(encoded)\n",
    "        return reconstructed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "autoencoder = Autoencoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
    "opt = tf.optimizers.SGD(learning_rate=learning_rate, momentum=momentum)\n",
    "def loss(preds, real):\n",
    "    return tf.reduce_mean(tf.square(tf.subtract(preds, real)))\n",
    "\n",
    "def train(loss, model, opt, original):\n",
    "    with tf.GradientTape() as tape:\n",
    "        preds = model(original)\n",
    "        reconstruction_error = loss(preds, original)\n",
    "    gradients = tape.gradient(reconstruction_error, model.trainable_variables)\n",
    "    gradient_variables = zip(gradients, model.trainable_variables)\n",
    "    opt.apply_gradients(gradient_variables)\n",
    "  \n",
    "    return reconstruction_error"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def train_loop(model, opt, loss, dataset, epochs=20):\n",
    "    for epoch in range(epochs):\n",
    "        epoch_loss = 0\n",
    "        for step, batch_features in enumerate(dataset):\n",
    "            loss_values = train(loss, model, opt, batch_features)\n",
    "            epoch_loss += loss_values\n",
    "        model.loss.append(epoch_loss)\n",
    "        print('Epoch {}/{}. Loss: {}'.format(epoch + 1, epochs, epoch_loss.numpy()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/50. Loss: 5.158796310424805\n",
      "Epoch 2/50. Loss: 3.0726304054260254\n",
      "Epoch 3/50. Loss: 2.94669771194458\n",
      "Epoch 4/50. Loss: 2.894327402114868\n",
      "Epoch 5/50. Loss: 2.8687782287597656\n",
      "Epoch 6/50. Loss: 2.870492935180664\n",
      "Epoch 7/50. Loss: 2.820152997970581\n",
      "Epoch 8/50. Loss: 2.830281972885132\n",
      "Epoch 9/50. Loss: 2.8133137226104736\n",
      "Epoch 10/50. Loss: 2.8230936527252197\n",
      "Epoch 11/50. Loss: 2.796506643295288\n",
      "Epoch 12/50. Loss: 2.8088817596435547\n",
      "Epoch 13/50. Loss: 2.8151283264160156\n",
      "Epoch 14/50. Loss: 2.8110859394073486\n",
      "Epoch 15/50. Loss: 2.786607265472412\n",
      "Epoch 16/50. Loss: 2.8005685806274414\n",
      "Epoch 17/50. Loss: 2.807785749435425\n",
      "Epoch 18/50. Loss: 2.816632032394409\n",
      "Epoch 19/50. Loss: 2.778759241104126\n",
      "Epoch 20/50. Loss: 2.8042068481445312\n",
      "Epoch 21/50. Loss: 2.8046441078186035\n",
      "Epoch 22/50. Loss: 2.804940700531006\n",
      "Epoch 23/50. Loss: 2.788064956665039\n",
      "Epoch 24/50. Loss: 2.7944788932800293\n",
      "Epoch 25/50. Loss: 2.815552234649658\n",
      "Epoch 26/50. Loss: 2.797698974609375\n",
      "Epoch 27/50. Loss: 2.800128221511841\n",
      "Epoch 28/50. Loss: 2.7927215099334717\n",
      "Epoch 29/50. Loss: 2.79184889793396\n",
      "Epoch 30/50. Loss: 2.7880537509918213\n",
      "Epoch 31/50. Loss: 2.8018202781677246\n",
      "Epoch 32/50. Loss: 2.822197914123535\n",
      "Epoch 33/50. Loss: 2.7898504734039307\n",
      "Epoch 34/50. Loss: 2.8130009174346924\n",
      "Epoch 35/50. Loss: 2.7675364017486572\n",
      "Epoch 36/50. Loss: 2.827432632446289\n",
      "Epoch 37/50. Loss: 2.80202579498291\n",
      "Epoch 38/50. Loss: 2.786804676055908\n",
      "Epoch 39/50. Loss: 2.8008463382720947\n",
      "Epoch 40/50. Loss: 2.8028457164764404\n",
      "Epoch 41/50. Loss: 2.7817986011505127\n",
      "Epoch 42/50. Loss: 2.7839791774749756\n",
      "Epoch 43/50. Loss: 2.8181684017181396\n",
      "Epoch 44/50. Loss: 2.798426866531372\n",
      "Epoch 45/50. Loss: 2.7929301261901855\n",
      "Epoch 46/50. Loss: 2.775773525238037\n",
      "Epoch 47/50. Loss: 2.786076068878174\n",
      "Epoch 48/50. Loss: 2.7812163829803467\n",
      "Epoch 49/50. Loss: 2.798339605331421\n",
      "Epoch 50/50. Loss: 2.7741923332214355\n"
     ]
    }
   ],
   "source": [
    "autoencoder = Autoencoder(hidden_dim=hidden_dim, original_dim=original_dim)\n",
    "opt = tf.keras.optimizers.Adam(learning_rate=1e-2)\n",
    "\n",
    "train_loop(autoencoder, opt, loss, training_dataset, epochs=max_epochs)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "plt.plot(range(max_epochs), autoencoder.loss)\n",
    "plt.xlabel('Epochs')\n",
    "plt.ylabel('Loss')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAABGoAAADjCAYAAADdR/IFAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4zLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvnQurowAAIABJREFUeJzt3XecVFXS8PEaAQkqCAgCkpPknBRBMGHCBEbUVRRdw2NGfdRn17TufnTXnFZ3TaiIIhgQUUEBEZAgQbKAIEiQJIqAEub9w9ei6jDd9Mx099zp/n3/qus503OWO7f79t1TVTm5ubkCAAAAAACAordfUS8AAAAAAAAAv+NBDQAAAAAAQETwoAYAAAAAACAieFADAAAAAAAQETyoAQAAAAAAiAge1AAAAAAAAEREyXiDOTk59O4uOutzc3OrJOOFOI9FJzc3NycZr8M5LFJcixmAazEjcC1mAK7FjMC1mAG4FjMC12IGiHUtsqMmupYX9QIAiAjXIhAVXItANHAtAtHAtZjBeFADAAAAAAAQETyoAQAAAAAAiAge1AAAAAAAAEQED2oAAAAAAAAiggc1AAAAAAAAEcGDGgAAAAAAgIjgQQ0AAAAAAEBElCzqBSB73HLLLRqXLVvWjbVq1Urjvn37xnyNZ555RuNJkya5sUGDBhV2iQAAAAAAFCl21AAAAAAAAEQED2oAAAAAAAAiggc1AAAAAAAAEUGNGqTUkCFDNI5Xe8bavXt3zLErr7xS4+OOO86NjRs3TuPvvvsu0SWiCDVu3NgdL1iwQOPrr79e4yeeeCJta8p2BxxwgMYPPfSQxvbaExGZPn26xmeffbYbW758eYpWBwAAkH4VK1bUuHbt2gn9THg/dOONN2o8Z84cjRctWuTmzZo1qyBLRIZhRw0AAAAAAEBE8KAGAAAAAAAgIkh9QlLZVCeRxNOdbMrLRx99pHH9+vXdvN69e2vcoEEDN9avXz+N//73vyf0e1G02rZt645t2tvKlSvTvRyISPXq1TUeMGCAxmFKYvv27TU+9dRT3dhTTz2VotXhD+3atdN42LBhbqxu3bop+70nnHCCO54/f77GK1asSNnvRWLsZ6SIyHvvvafxtddeq/Gzzz7r5u3atSu1C8swVatW1fjNN9/UeOLEiW7ec889p/GyZctSvq4/VKhQwR13795d41GjRmm8Y8eOtK0JKA5OOeUUjU877TQ31qNHD40bNmyY0OuFKU116tTRuHTp0jF/rkSJEgm9PjIbO2oAAAAAAAAiggc1AAAAAAAAEUHqEwqtQ4cOGp955pkx582dO1fjcDvh+vXrNd6yZYvG+++/v5s3efJkjVu3bu3GKleunOCKERVt2rRxx7/88ovGw4cPT/dyslKVKlXc8csvv1xEK0F+9OrVS+N426eTLUyt6d+/v8bnnXde2taBPexn39NPPx1z3pNPPqnxCy+84Ma2bduW/IVlENvtRcTfz9g0o7Vr17p5RZXuZLvyifj3eZu2unjx4tQvrBgqX768O7bp9C1atNA47D5KKll02XIJ11xzjcY2xVtEpGzZshrn5OQU+veG3U2B/GBHDQAAAAAAQETwoAYAAAAAACAieFADAAAAAAAQEWmtURO2arZ5gatWrXJj27dv1/i1117TeM2aNW4e+bVFz7bzDfM5bR63ramwevXqhF775ptvdsfNmjWLOfeDDz5I6DVRtGx+t20XKyIyaNCgdC8nK1133XUan3HGGW6sU6dO+X492/pVRGS//fb8fwCzZs3SePz48fl+bexRsuSej+yTTz65SNYQ1r646aabND7ggAPcmK05hdSx11/NmjVjzhs8eLDG9h4LeTvkkEM0HjJkiBurVKmSxrYu0P/8z/+kfmEx3HXXXRrXq1fPjV155ZUac9+ct379+mn8t7/9zY3VqlUrz58Ja9ls2LAh+QtDUtj3xuuvvz6lv2vBggUa2+9BSC7bIt2+X4v4mqm2rbqIyO7duzV+9tlnNf7iiy/cvCi8V7KjBgAAAAAAICJ4UAMAAAAAABARaU19evDBB91x3bp1E/o5u2Xz559/dmPp3FK2cuVKjcP/LdOmTUvbOqLm/fff19huQxPx52vjxo35fu2w3WupUqXy/RqIliZNmmgcpkqE28uRGo888ojGdgtoQZ111lkxj5cvX67xueee6+aFaTSIr2fPnhofccQRGoefR6kUtim26ajlypVzY6Q+pUbYjv3OO+9M6Odsamlubm5S15SJ2rVrp3G4dd66995707CavTVv3twd21Tx4cOHuzE+W/Nm02EeffRRjW3Le5HY18sTTzzhjm06d0HuebFvYYqLTWOyqSujRo1y83799VeNN2/erHH4OWXvSz/++GM3NmfOHI2/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9dK4QYMGbl62tl3/5z//qfFNN92U8M/Z98arr746zzhZ7PVnSzacd955Sf9dmS5MJbLXR0G88sor7jhe6pNNObd/ay+99JKbZ9t/FxV21AAAAAAAAEQED2oAAAAAAAAiggc1AAAAAAAAEZE1NWoGDhyocdgidtSoURpPnDgxbWvKRDfffLM77tixY57z3nnnHXdMS+7i75JLLtHYtvr98MMPi2A1SKc777zTHdsWpfEsW7ZM4z/96U9uzLZgzCb2vTBs03vKKadoPHjw4Hy/9vr1692xrYVxyCGHJPQaYQ43UidWi/Qwt//f//53OpaDJDr77LPd8cUXX6yxrZ8gsnd7WiSPba9tr7cLLrjAzbPXnK0nZGvShO677z533LRpU41PO+20PF9PZO/Pwmxha5QMGTLEjb3++usalyzpv7rWqlVL43i1vJLB1uOzfy+2RbiIyP3335/SdeB3t956q8b5qRP05z//WeOC3EulEztqAAAAAAAAIoIHNQAAAAAAABGRsalPdou4iMj//d//afzTTz+5sXvvvTcta8oGibbUu/baa90xLbmLvzp16uT53zdt2pTmlSAdRo4cqfHhhx9eoNeYN2+exhMmTCj0mjLBggULNLatY0VE2rRpo3HDhg3z/dq2/Wzo5Zdfdsf9+vXLc17YThzJU7NmTXccpl/8YeXKle542rRpKVsTUuOkk06KOTZixAh3/NVXX6V6ORCfBmXjggrfK206j0196tmzp5tXqVIljcN24pnMtkIO39MaN24c8+eOPfZYjUuVKqXx3Xff7ebFKsVQUDY1uX379kl9bcR2+eWXa2xTzsKUOGvu3LnueNiwYclfWIqwowYAAAAAACAieFADAAAAAAAQERmV+lS5cmWNH3/8cTdWokQJje2WfRGRyZMnp3Zh2Ivd2ikismPHjny/xubNm2O+ht3+WKFChZivcfDBB7vjRFO37BbN2267zY1t3bo1odfINKeeemqe//39999P80qyl92KG6/7Qbxt988995zGNWrUiDnPvv7u3bsTXaLTu3fvAv1ctpo5c2aecTIsXbo0oXktWrRwx3PmzEnqOrLZkUce6Y5jXcNh10QUP+F78C+//KLxv/71r3QvB2nw5ptvamxTn84991w3z5YGoDTDvo0ZMybP/25ThUV86tPOnTs1fvHFF928559/XuMbbrjBjcVK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\n",
      "text/plain": [
       "<Figure size 1440x288 with 20 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "number = 10  # how many digits we will display\n",
    "plt.figure(figsize=(20, 4))\n",
    "for index in range(number):\n",
    "    # display original\n",
    "    ax = plt.subplot(2, number, index + 1)\n",
    "    plt.imshow(x_test[index].reshape(28, 28), cmap='gray')\n",
    "    ax.get_xaxis().set_visible(False)\n",
    "    ax.get_yaxis().set_visible(False)\n",
    "\n",
    "    # display reconstruction\n",
    "    ax = plt.subplot(2, number, index + 1 + number)\n",
    "    plt.imshow(autoencoder(x_test)[index].numpy().reshape(28, 28), cmap='gray')\n",
    "    ax.get_xaxis().set_visible(False)\n",
    "    ax.get_yaxis().set_visible(False)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [conda env:tf2p0alpha]",
   "language": "python",
   "name": "conda-env-tf2p0alpha-py"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
